home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 367_01 / futi14as.zoo / cp.c < prev    next >
C/C++ Source or Header  |  1992-02-22  |  23KB  |  954 lines

  1. /*  cp.c  -- file copying (main routines)
  2.     Copyright (C) 1989, 1990 Free Software Foundation.
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.     Written by Torbjorn Granlund and David MacKenzie. */
  19.  
  20. /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  21.    This port is also distributed under the terms of the
  22.    GNU General Public License as published by the
  23.    Free Software Foundation.
  24.  
  25.    Please note that this file is not identical to the
  26.    original GNU release, you should have received this
  27.    code as patch to the official release.  */
  28.  
  29. static char RCS_Id[] =
  30.   "$Header: e:/gnu/fileutil/RCS/cp.c 1.4.0.2 90/09/19 11:18:06 tho Exp $";
  31.  
  32. static char Program_Id[] = "cp";
  33. static char RCS_Revision[] = "$Revision: 1.4.0.2 $";
  34.  
  35. #define VERSION \
  36.   "GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
  37.   (sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
  38.  
  39. #define COPYING \
  40.   "This is free software, distributed under the terms of the\n" \
  41.   "GNU General Public License.  For details, see the file COPYING.\n"
  42.  
  43. /* Yet to be done:
  44.  
  45.  * Symlink translation. */
  46.  
  47. #include <stdio.h>
  48. #include <getopt.h>
  49. #include "cp.h"
  50. #include "backupfile.h"
  51.  
  52. #ifdef MSDOS
  53. #include <assert.h>
  54.  
  55. extern enum backup_type get_version (char *version);
  56. extern char *savedir (char *dir, unsigned name_size);
  57.  
  58. #define strip_trailing_slashes(path)    strip_trailing_slashes (&path)
  59. #define is_ancestor(statb, ancestors)    0
  60. #define hash_init(module, size)
  61. #define remember_copied(path, ino, dev)    NULL
  62. #define remember_created(path)        0
  63. #define forget_all()
  64. char new_file;
  65.  
  66. #endif
  67.  
  68. #ifdef MKFIFO_MISSING
  69. /* This definition assumes that MODE has the S_IFIFO bit set. */
  70. #define mkfifo(path, mode) (mknod ((path), (mode), 0))
  71. #endif
  72.  
  73. enum backup_type get_version ();
  74. int eaccess_stat ();
  75.  
  76. /* Initial number of entries in each hash table entry's table of inodes.  */
  77. #define INITIAL_HASH_MODULE 100
  78.  
  79. /* Initial number of entries in the inode hash table.  */
  80. #define INITIAL_ENTRY_TAB_SIZE 70
  81.  
  82. /* A pointer to either lstat or stat, depending on
  83.    whether dereferencing of symlinks is done.  */
  84. #ifdef MSDOS
  85. int (*xstat) (char *, struct stat *);
  86. #else
  87. int (*xstat) ();
  88. #endif
  89.  
  90. /* The invocation name of this program.  */
  91. char *program_name;
  92.  
  93. /* If nonzero, copy all files except directories and, if not dereferencing
  94.    them, symbolic links, as if they were regular files. */
  95. int flag_copy_as_regular = 1;
  96.  
  97. /* If nonzero, dereference symbolic links (copy the files they point to). */
  98. int flag_dereference = 1;
  99.  
  100. /* If nonzero, remove existing target nondirectories. */
  101. int flag_force = 0;
  102.  
  103. /* If nonzero, query before overwriting existing targets with regular files. */
  104. int flag_interactive = 0;
  105.  
  106. /* If nonzero, give the copies the original files' permissions,
  107.    ownership, and timestamps. */
  108. int flag_preserve = 0;
  109.  
  110. /* If nonzero, copy directories recursively and copy special files
  111.    as themselves rather than copying their contents. */
  112. int flag_recursive = 0;
  113.  
  114. /* If nonzero, when copying recursively, skip any subdirectories that are
  115.    on different filesystems from the one we started on. */
  116. int flag_one_file_system = 0;
  117.  
  118. /* If nonzero, do not copy a nondirectory that has an existing destination
  119.    with the same or newer modification time. */
  120. int flag_update = 0;
  121.  
  122. /* If nonzero, display the names of the files before copying them. */
  123. int flag_verbose = 0;
  124.  
  125. /* The error code to return to the system. */
  126. int exit_status = 0;
  127.  
  128. /* The bits to preserve in created files' modes. */
  129. int umask_kill;
  130.  
  131. struct option long_opts[] =
  132. {
  133. #ifdef MSDOS
  134.   {"copying", 0, NULL, 30},
  135.   {"version", 0, NULL, 31},
  136. #endif
  137.   {"backup", 0, NULL, 'b'},
  138.   {"force", 0, NULL, 'f'},
  139.   {"interactive", 0, NULL, 'i'},
  140.   {"no-dereference", 0, &flag_dereference, 0},
  141.   {"one-file-system", 0, &flag_one_file_system, 1},
  142.   {"preserve", 0, &flag_preserve, 1},
  143.   {"recursive", 0, NULL, 'R'},
  144.   {"suffix", 1, NULL, 'S'},
  145.   {"update", 0, &flag_update, 1},
  146.   {"verbose", 0, &flag_verbose, 1},
  147.   {"version-control", 1, NULL, 'V'},
  148.   {NULL, 0, NULL, 0}
  149. };
  150.  
  151. void
  152. main (argc, argv)
  153.      int argc;
  154.      char *argv[];
  155. {
  156.   int c;
  157.   int ind;
  158.   int make_backups = 0;
  159.   char *version;
  160.  
  161.   program_name = argv[0];
  162.  
  163.   version = getenv ("SIMPLE_BACKUP_SUFFIX");
  164.   if (version)
  165.     simple_backup_suffix = version;
  166.   version = getenv ("VERSION_CONTROL");
  167.  
  168.   /* Find out the current file creation mask, to knock the right bits
  169.      when using chmod.  The creation mask is set to to be liberal, so
  170.      that created directories can be written, even if it would not
  171.      have been allowed with the mask this process was started with.  */
  172.  
  173. #ifdef MSDOS            /* not 100%ly correct ... */
  174.   umask_kill = 07777 ^ umask (0);
  175. #else
  176.   umask_kill = 0777777 ^ umask (0);
  177. #endif
  178.  
  179.   while ((c = getopt_long (argc, argv, "bdfipruvxRS:V:", long_opts, &ind))
  180.      != EOF)
  181.     {
  182.       switch (c)
  183.     {
  184.     case 0:
  185.       break;
  186.  
  187.     case 'b':
  188.       make_backups = 1;
  189.       break;
  190.  
  191.     case 'd':
  192.       flag_dereference = 0;
  193.       break;
  194.  
  195.     case 'f':
  196.       flag_force = 1;
  197.       flag_interactive = 0;
  198.       break;
  199.  
  200.     case 'i':
  201.       flag_force = 0;
  202.       flag_interactive = 1;
  203.       break;
  204.  
  205.     case 'p':
  206.       flag_preserve = 1;
  207.       break;
  208.  
  209.     case 'r':
  210.       flag_recursive = 1;
  211.       flag_copy_as_regular = 1;
  212.       break;
  213.  
  214.     case 'R':
  215.       flag_recursive = 1;
  216.       flag_copy_as_regular = 0;
  217.       break;
  218.  
  219.     case 'u':
  220.       flag_update = 1;
  221.       break;
  222.  
  223.     case 'v':
  224.       flag_verbose = 1;
  225.       break;
  226.  
  227.     case 'x':
  228.       flag_one_file_system = 1;
  229.       break;
  230.  
  231.     case 'S':
  232.       simple_backup_suffix = optarg;
  233.       break;
  234.  
  235.     case 'V':
  236.       version = optarg;
  237.       break;
  238.  
  239. #ifdef MSDOS
  240.     case 30:
  241.       fprintf (stderr, COPYING);
  242.       exit (0);
  243.       break;
  244.  
  245.     case 31:
  246.       fprintf (stderr, VERSION);
  247.       exit (0);
  248.       break;
  249. #endif
  250.  
  251.     default:
  252.       usage ((char *) 0);
  253.     }
  254.     }
  255.  
  256.   if (make_backups)
  257.     backup_type = get_version (version);
  258.  
  259.   if (flag_preserve == 1)
  260. #ifdef MSDOS            /* not 100%ly correct ... */
  261.     umask_kill = 07777;
  262. #else
  263.     umask_kill = 0777777;
  264. #endif
  265.  
  266.   /* The key difference between -d (+no-dereference) and not is the version
  267.      of `stat' to call.  */
  268.  
  269.   if (flag_dereference)
  270.     xstat = stat;
  271.   else
  272.     xstat = lstat;
  273.  
  274.   /* Allocate space for remembering copied and created files.  */
  275.  
  276.   hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
  277.  
  278.   exit_status |= do_copy (argc, argv);
  279.  
  280.   exit (exit_status);
  281. }
  282.  
  283. /* Scan the arguments, and copy each by calling copy.
  284.    Return 0 if successful, 1 if any errors occur. */
  285.  
  286. int
  287. do_copy (argc, argv)
  288.      int argc;
  289.      char *argv[];
  290. {
  291.   char *target;
  292.   struct stat sb;
  293.   int new_dst = 0;
  294.   int ret = 0;
  295.  
  296.   if (optind >= argc)
  297.     usage ("missing file arguments");
  298.   if (optind >= argc - 1)
  299.     usage ("missing file argument");
  300.  
  301.   target = argv[argc - 1];
  302.  
  303.   strip_trailing_slashes (target);
  304.  
  305.   if (lstat (target, &sb))
  306.     {
  307.       if (errno != ENOENT)
  308.     {
  309.       error (0, errno, "%s", target);
  310.       return 1;
  311.     }
  312.       else
  313.     new_dst = 1;
  314.     }
  315.   else
  316.     {
  317.       struct stat sbx;
  318.  
  319.       /* If `target' is not a symlink to a nonexistent file, use
  320.      the results of stat instead of lstat, so we can copy files
  321.      into symlinks to directories. */
  322.       if (stat (target, &sbx) == 0)
  323.     sb = sbx;
  324.     }
  325.  
  326.   if (!new_dst && (sb.st_mode & S_IFMT) == S_IFDIR)
  327.     {
  328.       /* cp e_file_1...e_file_n e_dir
  329.      copy the files `e_file_1' through `e_file_n